package cn.iocoder.yudao.framework.common.util.world;

import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.BreakIterator;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 精确字数统计工具类。
 * 包含针对纯文本、PDF、Excel 文件的内容提取和统计功能。
 * 针对中文使用 Jieba 分词以提高准确性。
 * 兼容 Java 8 及以上版本。
 */
public class WordCountUtils {

    // 初始化 Jieba 分词器
    private static final JiebaSegmenter jiebaSegmenter = new JiebaSegmenter();

    // 正则表达式：匹配连续的英文字母
    private static final Pattern ENGLISH_WORD_PATTERN = Pattern.compile("[a-zA-Z]+");
    // 正则表达式：匹配连续的数字
    private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");

    /**
     * 统计文本的字符数（包括所有字符，如空格、标点）。
     *
     * @param text 输入文本
     * @return 字符数
     */
    public static int countCharacters(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }
        return text.length();
    }

    /**
     * 统计文本的单词数（英文）和词数（中文）。
     * 使用 Jieba 进行中文分词。
     * 这是推荐的高精度统计方法。
     *
     * @param text 输入文本
     * @return 估算的字/词数
     */
    public static int countWordsAdvanced(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }

        int wordCount = 0;
        // 1. 使用 Jieba 对整个文本进行中文分词
        List<SegToken> tokens = jiebaSegmenter.process(text, JiebaSegmenter.SegMode.INDEX);
        for (SegToken token : tokens) {
            String word = token.word.trim();
            if (!word.isEmpty()) {
                // Jieba 会处理中英文混合的情况，我们直接计数每个分出的词
                wordCount++;
            }
        }
        return wordCount;
    }

    /**
     * 统计文本的单词数（英文）和词数（中文）。
     * 使用正则表达式分别统计中文汉字、英文单词和数字序列。
     * 这是模拟 WPS 逻辑的简化方法。
     *
     * @param text 输入文本
     * @return 估算的字数
     */
    public static int countWordsWPSSimple(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }

        int count = 0;

        // 统计中文汉字
        Matcher chineseMatcher = Pattern.compile("\\p{InCJK_Unified_Ideographs}").matcher(text);
        while (chineseMatcher.find()) {
            count++;
        }

        // 统计英文单词 (连续字母)
        Matcher englishMatcher = ENGLISH_WORD_PATTERN.matcher(text);
        while (englishMatcher.find()) {
            count++;
        }

        // 统计数字序列 (连续数字)
        Matcher numberMatcher = NUMBER_PATTERN.matcher(text);
        while (numberMatcher.find()) {
            count++;
        }

        return count;
    }

    // --- 文件内容提取和统计方法 ---

    /**
     * 从文件路径读取文件内容并统计。
     * 支持 .txt, .pdf, .xlsx, .xls
     * @param filePath 文件路径
     * @return 统计结果对象
     * @throws IOException 文件读取或处理错误
     */
    public static WordCountResult countWordsFromFile(String filePath) throws IOException {
        Path path = new File(filePath).toPath(); // Java 8 兼容方式获取 Path
        String fileName = path.getFileName().toString();
        String extension = getFileExtension(fileName).toLowerCase();

        String content;
        switch (extension) {
            case "txt":
                content = readTextFile(path.toFile()); // 使用 Java 8 兼容方法
                break;
            case "pdf":
                content = readPdfFile(path);
                break;
            case "xlsx":
                content = readExcelFile(path, true); // .xlsx
                break;
            case "xls":
                content = readExcelFile(path, false); // .xls
                break;
            default:
                throw new IOException("不支持的文件类型: " + extension);
        }

        return performWordCount(content, fileName);
    }

    /**
     * 从 InputStream 读取文件内容并统计。
     * 需要提供文件名以确定类型。
     * @param inputStream 文件输入流
     * @param fileName 原始文件名 (用于判断类型)
     * @return 统计结果对象
     * @throws IOException 文件读取或处理错误
     */
    public static WordCountResult countWordsFromFileStream(InputStream inputStream, String fileName) throws IOException {
        String extension = getFileExtension(fileName).toLowerCase();

        String content;
        switch (extension) {
            case "txt":
                content = readTextFile(inputStream);
                break;
            case "pdf":
                content = readPdfFile(inputStream);
                break;
            case "xlsx":
                content = readExcelFile(inputStream, true); // .xlsx
                break;
            case "xls":
                content = readExcelFile(inputStream, false); // .xls
                break;
            default:
                throw new IOException("不支持的文件类型: " + extension);
        }

        return performWordCount(content, fileName);
    }

    // --- 内部辅助方法 ---

    private static String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
            return fileName.substring(lastDotIndex + 1);
        }
        return "";
    }

    private static WordCountResult performWordCount(String content, String fileName) {
        int characters = countCharacters(content);
        int wordsWps = countWordsWPSSimple(content);
        int wordsAdvanced = countWordsAdvanced(content);
        return new WordCountResult(fileName, characters, wordsWps, wordsAdvanced);
    }

    // --- 文件读取实现 (兼容 Java 8) ---

    // 兼容 Java 8: 使用 BufferedReader 和 InputStreamReader
    private static String readTextFile(File file) throws IOException {
        StringBuilder contentBuilder = new StringBuilder();
        // 使用 try-with-resources 确保资源关闭
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append(System.lineSeparator()); // 保留换行符
            }
        }
        return contentBuilder.toString();
    }

    private static String readTextFile(InputStream inputStream) throws IOException {
        StringBuilder contentBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append(System.lineSeparator()); // 保留换行符
            }
        }
        return contentBuilder.toString();
    }

    private static String readPdfFile(Path path) throws IOException {
        try (PDDocument document = PDDocument.load(path.toFile())) {
            PDFTextStripper pdfStripper = new PDFTextStripper();
            return pdfStripper.getText(document);
        }
    }

    private static String readPdfFile(InputStream inputStream) throws IOException {
        try (PDDocument document = PDDocument.load(inputStream)) {
            PDFTextStripper pdfStripper = new PDFTextStripper();
            return pdfStripper.getText(document);
        }
    }

    private static String readExcelFile(Path path, boolean isXlsx) throws IOException {
        try (InputStream inputStream = Files.newInputStream(path);
             Workbook workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
            return extractTextFromWorkbook(workbook);
        }
    }

    private static String readExcelFile(InputStream inputStream, boolean isXlsx) throws IOException {
        try (Workbook workbook = isXlsx ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream)) {
            return extractTextFromWorkbook(workbook);
        }
    }

    private static String extractTextFromWorkbook(Workbook workbook) {
        StringBuilder textBuilder = new StringBuilder();
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            for (Row row : sheet) {
                for (Cell cell : row) {
                    switch (cell.getCellType()) {
                        case STRING:
                            textBuilder.append(cell.getStringCellValue()).append(" ");
                            break;
                        case NUMERIC:
                            if (DateUtil.isCellDateFormatted(cell)) {
                                // 可以选择如何处理日期
                                textBuilder.append(cell.getDateCellValue().toString()).append(" ");
                            } else {
                                textBuilder.append(cell.getNumericCellValue()).append(" ");
                            }
                            break;
                        case BOOLEAN:
                            textBuilder.append(cell.getBooleanCellValue()).append(" ");
                            break;
                        case FORMULA:
                            // 获取公式计算结果，根据结果类型处理
                            switch (cell.getCachedFormulaResultType()) {
                                case STRING:
                                    textBuilder.append(cell.getStringCellValue()).append(" ");
                                    break;
                                case NUMERIC:
                                    if (DateUtil.isCellDateFormatted(cell)) {
                                        textBuilder.append(cell.getDateCellValue().toString()).append(" ");
                                    } else {
                                        textBuilder.append(cell.getNumericCellValue()).append(" ");
                                    }
                                    break;
                                case BOOLEAN:
                                    textBuilder.append(cell.getBooleanCellValue()).append(" ");
                                    break;
                                case BLANK:
                                    break;
                                default:
                                    // 公式错误或其他情况，可以忽略或记录
                                    break;
                            }
                            break;
                        case BLANK:
                            break;
                        default:
                            // 其他类型，如错误，可以忽略
                            break;
                    }
                }
                textBuilder.append("\n"); // 每行结束后换行
            }
            textBuilder.append("\n--- Sheet Separator ---\n"); // 分隔不同工作表
        }
        return textBuilder.toString();
    }

    // --- 结果封装类 (传统 Java 类版本，兼容性更好) ---
    public static class WordCountResult {
        private final String fileName;
        private final int characterCount;
        private final int wordEstimateWPS;
        private final int wordCountAdvanced;

        public WordCountResult(String fileName, int characterCount, int wordEstimateWPS, int wordCountAdvanced) {
            this.fileName = fileName;
            this.characterCount = characterCount;
            this.wordEstimateWPS = wordEstimateWPS;
            this.wordCountAdvanced = wordCountAdvanced;
        }

        public String fileName() {
            return fileName;
        }

        public long characterCount() {
            return characterCount;
        }

        public int wordEstimateWPS() {
            return wordEstimateWPS;
        }

        public int wordCountAdvanced() {
            return wordCountAdvanced;
        }

        @Override
        public String toString() {
            return String.format(
                    "文件名: %s\n字符数 (含空格/换行): %d\n估算字数 (模拟WPS): %d\n字/词数 (高级Jieba): %d",
                    fileName, characterCount, wordEstimateWPS, wordCountAdvanced
            );
        }
    }

    // --- 示例 / 测试 ---
    public static void main(String[] args) {
        // --- 纯文本字符串测试 ---
        String testText = "你好，世界！阿萨斯`";
        System.out.println("=== 纯文本测试 ===");
        System.out.println("测试文本: " + testText);
        System.out.println("--- 统计结果 ---");
        System.out.println("字符数 (含空格/标点): " + countCharacters(testText));
        System.out.println("字数 (模拟WPS简单规则): " + countWordsWPSSimple(testText));
        System.out.println("字/词数 (高级Jieba分词): " + countWordsAdvanced(testText));
        System.out.println("英文单词数 (BreakIterator): " + countEnglishWordsOnly(testText));
        System.out.println("==================\n");

        // --- 文件测试 (请替换为你的实际文件路径) ---
        // String pdfPath = "sample.pdf";
        // String excelPath = "sample.xlsx";
        // String txtPath = "sample.txt";

        // try {
        //     System.out.println("--- 统计 PDF 文件 ---");
        //     WordCountResult pdfResult = WordCountUtils.countWordsFromFile(pdfPath);
        //     System.out.println(pdfResult);
        //     System.out.println("--------------------\n");

        //     System.out.println("--- 统计 Excel 文件 ---");
        //     WordCountResult excelResult = WordCountUtils.countWordsFromFile(excelPath);
        //     System.out.println(excelResult);
        //     System.out.println("----------------------\n");

        //     System.out.println("--- 统计 TXT 文件 ---");
        //     WordCountResult txtResult = WordCountUtils.countWordsFromFile(txtPath);
        //     System.out.println(txtResult);
        //     System.out.println("---------------------\n");


        // } catch (IOException e) {
        //     System.err.println("处理文件时发生错误: " + e.getMessage());
        //     e.printStackTrace();
        // }
    }

    /**
     * 统计文本的单词数（仅英文）。
     * 使用 Java 内置的 BreakIterator，适用于纯英文或多语言文本中的英文部分。
     * 注意：此方法未在文件处理流程中使用，仅为提供额外功能。
     *
     * @param text 输入文本
     * @return 英文单词数
     */
    public static int countEnglishWordsOnly(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }

        BreakIterator wordIterator = BreakIterator.getWordInstance(Locale.ENGLISH);
        wordIterator.setText(text);
        int count = 0;
        int start = wordIterator.first();
        int end = wordIterator.next();

        while (end != BreakIterator.DONE) {
            String word = text.substring(start, end).trim();
            // BreakIterator 会分出标点和空格，只计算非空且包含字母的部分
            if (!word.isEmpty() && word.chars().anyMatch(Character::isLetter)) {
                count++;
            }
            start = end;
            end = wordIterator.next();
        }

        return count;
    }
}



